#ifndef DATAMAKER_H
#define DATAMAKER_H

//Test

#include <src\projectHeaders.h>
#include <fstream>

class DataMaker {
public:
    /**
     * @brief 单例模式
     * @return DataMaker单例
     */
    static DataMaker &GetInstance() {
        static DataMaker instance;
        return instance;
    }

    void InitParas(int n, int m) {
        this->n = n;
        this->m = m;
    }

    /**
     * @brief 生成指定区间内的随机数
     * @param l
     * @param r
     * @return 区间内的随机数
     */
    static int Rand(int l, int r) {
        return (double) rand() / RAND_MAX * (r - l) + l;
    }

    void SpawnData() {
        dataFile.open("data.in", std::ios::out);

        isSuccessful = true;

        srand(time(0));
        //int n = (N == -1 ? rand(2, 1000) : N);
        //int m = (M == -1 ? rand(2, 1000) : M);

        auto check = [&]() {
            int dx[4] = {0, 1, 0, -1};
            int dy[4] = {1, 0, -1, 0};
            memset(tmp, 0, sizeof tmp);
            queue<pair<int, int>> q;
            q.push(start);
            tmp[start.first][start.second] = 1;
            while (q.size()) {
                pair<int, int> &now = q.front();
                q.pop();
                for (int i = 0; i < 4; i++) {
                    PII next = {now.first + dx[i], now.second + dy[i]};
                    if (0 <= next.first && next.first < n && 0 <= next.second && next.second < m)
                        if (mp[next.first][next.second] == 1 && tmp[next.first][next.second] == 0) {
                            q.push(next);
                            tmp[next.first][next.second] = 1;
                        }
                }
            }
            if (tmp[end.first][end.second] == 1) {
                // cout << "YES" << endl;
                return 1;
            } else {
                // cout << "NO" << endl;
                return 0;
            }
        };

        int try_number = 0;
        do {

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    mp[i][j] = (rand() % 4 ? 1 : 0);
                    // cout << mp[i][j] << ' ';
                }
            }

            do {
                start = {Rand(1, n-1), Rand(1, m-1)};
                end = {Rand(1, n-1), Rand(1, m-1)};
                // cout << "!" << endl;

            } while (start == end || mp[start.first][start.second] == 0 || mp[end.first][end.second] == 0 ||
                     abs(start.first - end.first) + abs(start.second - end.second) < (n + m) / 2);
            try_number++;
            if (try_number >= TRY) {
                isSuccessful = false;
                return;
            }
        } while (!check());

        dataFile << n << ' ' << m << ' ' << start.first << ' ' << start.second << ' ' << end.first << ' ' << end.second
                 << endl;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                dataFile << mp[i][j] << ' ';
            dataFile << endl;
        }
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) {
                int u, r, d, l;
                if (i - 1 >= 0)
                    u = Rand(1, isEdge ? edge_max : 1);
                else
                    u = -1;

                if (j + 1 < m)
                    r = Rand(1, isEdge ? edge_max : 1);
                else
                    r = -1;

                if (i + 1 < n)
                    d = Rand(1, isEdge ? edge_max : 1);
                else
                    d = -1;

                if (j - 1 >= 0)
                    l = Rand(1, isEdge ? edge_max : 1);
                else
                    l = -1;

                dataFile << u << ' ' << r << ' ' << d << ' ' << l << endl;
            }
        dataFile.close();
    }

    int mp[1000][1000];
    int n = 9; // 迷宫大小 行数
    int m = 9; // 迷宫大小 列数
    pair<int, int> start{0, 0}, end{0, 0};

    bool isSuccessful;
    bool isEdge = false;        // 1:通路有代价   0:通路代价默认为1

private:

    const int TRY = 80000;       // 最大尝试次数

    const int edge_max = 10; // 通路代价最大值

    int tmp[1000][1000];

    ofstream dataFile;
};

#endif // DATAMAKER_H
